package generator.provider;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import generator.GeneratorConfig;
import generator.GeneratorParam;
import generator.Utility;
import org.apache.commons.collections4.CollectionUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.VerboseProgressCallback;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.config.*;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Created by luowei on 2017/8/4.
 */
public class MyDataSourceProvider implements DataSourceProvider {

	private static final Set<String> IGNORE_COLUMNS = ImmutableSet.of(
			"create_user_id",
			"create_time",
			"update_user_id",
			"update_time",
			"delete_flag"
	);

	private static IntrospectedTable getTableInfoByReflect(Context context) {
		List<IntrospectedTable> introspectedTables = null;
		try {
			Field field = context.getClass().getDeclaredField("introspectedTables");
			field.setAccessible(true);
			Object value = field.get(context);
			if (Objects.nonNull(value)) {
				introspectedTables = (List<IntrospectedTable>) value;
			}
		} catch (IllegalAccessException | NoSuchFieldException e) {
			e.printStackTrace();
			throw new RuntimeException("获取table信息失败", e);
		}

		if (CollectionUtils.isEmpty(introspectedTables)) {
			throw new RuntimeException("未获取到table信息");
		}

		return introspectedTables.get(0);
	}

	private static BaseTableModel transformBaseTableModel(IntrospectedTable introspectedTable, GeneratorParam param) {
		BaseTableModel baseModel = new BaseTableModel();

		List<ColumnInfo> cols = Lists.newArrayList();
		//生成列信息
		List<IntrospectedColumn> columnList = introspectedTable.getAllColumns();
		Set<String> importList = new HashSet<>();
		ColumnInfo columnInfo;
		FullyQualifiedJavaType javaType;
		for (IntrospectedColumn column : columnList) {
			columnInfo = new ColumnInfo();
			columnInfo.setName(column.getActualColumnName());
			columnInfo.setModelColumnName(Utility.underscoreToCamelCase(column.getActualColumnName()));
			columnInfo.setComment(column.getRemarks());
			javaType = column.getFullyQualifiedJavaType();
			columnInfo.setJavaType(javaType.getShortName());
			if (!IGNORE_COLUMNS.contains(column.getActualColumnName())) {
				addImportByJavaType(importList, javaType);
			}
			cols.add(columnInfo);
		}
		baseModel.setColumnInfoList(cols);

		String tableName = introspectedTable.getTableConfiguration().getTableName();
		baseModel.setTableName(tableName);
		baseModel.setPrefix(param.getPrefix());
		baseModel.setTableAlias(param.getTableAlias());

		String modelName = introspectedTable.getTableConfiguration().getDomainObjectName();
		baseModel.setModelName(modelName);
		baseModel.setModelNameLowerCamel(Utility.tableNameConvertLowerCamel(modelName));
		baseModel.setImportList(importList);
		return baseModel;
	}

	private static void addImportByJavaType(Set<String> importList, FullyQualifiedJavaType javaType) {
		if (javaType.getShortName().equals("LocalDateTime")) {
			importList.add("java.time.LocalDateTime");
		}
	}

	@Override
	public Map<String, Object> provide(GeneratorConfig configuration, GeneratorParam param) {
		Context context = new Context(ModelType.FLAT);
		context.setId("generator");
		context.setTargetRuntime("MyBatis3Simple");
		context.addProperty(PropertyRegistry.CONTEXT_BEGINNING_DELIMITER, "`");
		context.addProperty(PropertyRegistry.CONTEXT_ENDING_DELIMITER, "`");

		//读取数据库配置文件
		GeneratorConfig.DataSource dataSource = configuration.getDataSource();
		JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
		jdbcConnectionConfiguration.setConnectionURL(dataSource.getUrl());
		jdbcConnectionConfiguration.setUserId(dataSource.getUsername());
		jdbcConnectionConfiguration.setPassword(dataSource.getPassword());
		jdbcConnectionConfiguration.setDriverClass(dataSource.getDriverClassName());
		jdbcConnectionConfiguration.addProperty("nullCatalogMeansCurrent", "true");
		context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

		//自定义类型解析实现
		JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
		javaTypeResolverConfiguration.setConfigurationType(MyJavaTypeResolverImpl.class.getName());
		context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);

		TableConfiguration tableConfiguration = new TableConfiguration(context);
		tableConfiguration.setTableName(param.getTableName());
		tableConfiguration.setDomainObjectName(param.getModelName());
		context.addTableConfiguration(tableConfiguration);

		try {
			List<String> warnings = new ArrayList<>();
			Set<String> setTable = new HashSet<>();
			setTable.add(param.getTableName());
			context.introspectTables(new VerboseProgressCallback(), warnings, setTable);

			IntrospectedTable introspectedTable = getTableInfoByReflect(context);
			BaseTableModel baseTableModel = transformBaseTableModel(introspectedTable, param);
			return Utility.transBean2Map(baseTableModel);

		} catch (Exception e) {
			throw new RuntimeException("生成Model和Mapper失败", e);
		}
	}
}
